#include <cstdio>
#include <cstdlib>
//#include <tchar.h>

#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/video/video.hpp"
#include <opencv2/gpu/gpu.hpp>


#include "VideoRead.h"

#include "FeatureComputer.h"

#include "Classifier.h"

#include "Bagging.h"

class LcInterface
{
public:

	LcInterface();
	void input( int argc, char * const argv[]);

	LcClassifier*  getClassifier(){ return my_classifier;}

	LcVideoReadExt getTrainVideo();
	LcVideoReadExt getTestVideo();

	LcVideoRead * getTrainVideop();
	LcVideoRead * getTestVideop();


	bool IF_TRAIN;
	bool IF_TEST;

	int train_f_start;
	int train_f_end;
	int train_f_rate;

	int test_f_start;
	int test_f_end;
	int test_f_rate;

	string root;

	string train_video_name;
	string test_video_name;

	string feature_code_string;

	string classifier_name;

	void buildDatasetmap();

	map< string , Vec3i> data_map;

	bool setVideo( string name ,int & start, int & end , int & rate);
	void setClassifier();

	void init();

	string ext;
	

	LcClassifier* my_classifier;
	


};


LcVideoRead * LcInterface::getTrainVideop()
{
	LcVideoRead * ans;

	bool bo = false;
	bo = bo ||  ( ext == ".jpg" );
	bo = bo ||  ( ext == ".JPG" );
	bo = bo ||  ( ext == ".PNG" );
	bo = bo ||  ( ext == ".png" );
	if( bo )	
		ans = new LcImgRead;	
	else
		ans = new LcVideoReadExt;

	ans->video_name = train_video_name;
	ans->f_start = train_f_start;
	ans->f_end = train_f_end;
	ans->f_rate = train_f_rate;
	ans->t_win = 0;
	ans->root = root;
	ans->ext = ext;
	return ans;
}

LcVideoRead * LcInterface::getTestVideop()
{
	LcVideoRead * ans;

	bool bo = false;
	bo = bo ||  ( ext == ".jpg" );
	bo = bo ||  ( ext == ".JPG" );
	bo = bo ||  ( ext == ".PNG" );
	bo = bo ||  ( ext == ".png" );
	if( bo )
		ans = new LcImgRead;
	else
		ans = new LcVideoReadExt;

	ans->video_name = test_video_name;
	ans->f_start = test_f_start;
	ans->f_end = test_f_end;
	ans->f_rate = test_f_rate;
	ans->t_win = 0;
	ans->root = root;
	ans->ext = ext;

	return ans;
}

LcVideoReadExt LcInterface::getTrainVideo()
{
	LcVideoReadExt ans;
	ans.video_name = train_video_name;
	ans.f_start = train_f_start;
	ans.f_end = train_f_end;
	ans.f_rate = train_f_rate;
	ans.t_win = 0;
	ans.root = root;
	return ans;
}

LcVideoReadExt LcInterface::getTestVideo()
{
	LcVideoReadExt ans;
	ans.video_name = test_video_name;
	ans.f_start = test_f_start;
	ans.f_end = test_f_end;
	ans.f_rate = test_f_rate;
	ans.t_win = 0;
	ans.root = root;
	return ans;
}

void LcInterface::setClassifier()
{
	if(classifier_name == "rdt")
	{
		my_classifier = new LcRandomTrees;
	}
}
void LcInterface::init()
{
	if(IF_TEST == false)
	{
		if(train_f_start<0) train_f_start = test_f_start;
		if(train_f_end<0) train_f_end = test_f_end;
		if(train_f_rate<0) train_f_rate = test_f_rate;
	}

	if(feature_code_string == "") feature_code_string = "l";

	if(classifier_name == "" ) classifier_name = "rdt";
	setClassifier();

	if(train_video_name == "" ){train_video_name = "GOPR2382_cab";}
	setVideo( train_video_name, train_f_start, train_f_end, train_f_rate);

	if(test_video_name == "" ){test_video_name = "GOPR2384_cab";}
	setVideo( test_video_name, test_f_start, test_f_end, test_f_rate);
}

LcInterface::LcInterface()
{
	train_f_start = -1;
	train_f_rate = -1;
	train_f_end = -1;

	test_f_start = -1;
	test_f_rate = -1;
	test_f_end = -1;

	root = "./../_FGS/";
	train_video_name = "";
	test_video_name = "";
	feature_code_string = "";
	classifier_name = "";

	ext = ".avi";

	IF_TEST = false;
	IF_TRAIN = false;

	buildDatasetmap();
}

void LcInterface::buildDatasetmap()
{
	data_map.clear();
	data_map.insert( pair< string, Vec3i>( "GOPR2382_cab", Vec3i(150,5300,50)) );
	data_map.insert( pair< string, Vec3i>( "GOPR2384_cab", Vec3i(150,11200,25)) );
}

bool LcInterface::setVideo( string name ,int & start, int & end , int & rate)
{
	map<string , Vec3i>::iterator iter = data_map.find( name );
	if( iter != data_map.end())
	{
		Vec3i temp = iter->second;
		if(start<0)start = temp[0];
		if(end<0)end = temp[1];
		if(rate<0)rate = temp[2];
		return true;
	}
	else
	{
		cout << "One of Video is not in default" << endl;
		return false;
	}
}

void LcInterface::input( int argc, char * const argv[])
{
	for(int ind = 1;ind < argc;ind++)
	{
		/*** Parse switches ***/
		if (argv[ind][0] == '-') {
			switch (argv[ind][1]) {
				case 'f':
					root = string(argv[++ind]);
					break;
				case 't':
					train_video_name = string(argv[++ind]);
					break;

				case 'y':
					ext = string(argv[++ind]);
					break;
				case 'p':
					test_video_name = string(argv[++ind]);
					break;
				case 'v':
					feature_code_string =  string(argv[++ind]);
					break;
				case 'a':
					IF_TRAIN = true;
					break;
				case 'b':
					IF_TEST = true;
					break;
				case 's':
					//only for predict video setting , for trainning video it's always solid with frame
					// unless it's no testing model then the test frame setting will be use
					// as training parameter
					test_f_start =  atoi(argv[++ind]);
					break;
				case 'e':
					test_f_end = atoi(argv[++ind]);
					break;
				case 'r':
					test_f_rate = atoi(argv[++ind]);
					break;
				case 'c':
					classifier_name = string(argv[++ind]);
					break;

				default : printf("Unknown switch '%c'\n", argv[ind][1]);
				break;
			}
		}
	}

	init();
}


int main(int argc, char * const argv[])
{	

	LcInterface my_setting;

	if(argc==1)
	{
		//char *const setting_string[] ={ "","-a","-v","l","-t","GOPR2382_cab","-s", "550", "-e", "700", "-r","50","-p","GOPR2382_cab","-f","../../_FGS/"};

		//char *const setting_string[] ={ "","-a","-v","l","-t","P_01","-s", "1250", "-e", "19000", "-r","500","-p","P_01","-f","../../_FGS/","-y",".jpg"};
		char *const setting_string[] ={ "","-b","-v","l","-t","P_02","-s", "2000", "-e", "6000", "-r","2000","-p","P_02","-f","../../_FGS/","-y",".jpg"};

		//char *const setting_string[] ={ "","-b","-v","zselect_id","-t","GOPR2382_cab","-s", "550", "-e", "700", "-r","50","-p","GOPR2382_cab","-f","../../_FGS/"};
		//char *const setting_string[] ={ "","-b","-v","l","-t","GOPR2382_cab","-s", "550", "-e", "700", "-r","50","-p","GOPR2382_cab","-f","../../_FGS/"};

		my_setting.input( 17 + 1 ,setting_string);
	}
	else my_setting.input( argc, argv);
	
	LcBagging bagging;

	if(my_setting.IF_TRAIN)
	{
		LcVideoRead * my_reader = my_setting.getTrainVideop();
		bagging.setClassifier( my_setting.getClassifier());
		bagging.setFeatureCode( my_setting.feature_code_string.c_str() );
		bagging.setReader( my_reader );
		bagging.veb = 1;

		{
			FILE * fid = fopen("bagging_config.txt","r");
			int n_classifier; int instance_limit;
			fscanf(fid, "%d%d",&n_classifier, &instance_limit);
			bagging.n_classifier = n_classifier;
			bagging.instance_limit = instance_limit;
			fclose(fid);
		}

		bagging.train( *my_reader);

		{
			string saving_name = my_reader->root + "classifier_output/bagging/";
			bagging.save(saving_name.c_str());
		}
	}

	if(my_setting.IF_TEST)
	{
	
		//LcBagging bagging;
		
		LcVideoRead * train_reader = my_setting.getTrainVideop();
		LcVideoRead * test_reader = my_setting.getTestVideop();
				
		if(!my_setting.IF_TRAIN)
		{
		
			bagging.setClassifier( my_setting.getClassifier());
			bagging.setFeatureCode( my_setting.feature_code_string.c_str() );
			bagging.setReader( train_reader );

			bagging.veb = 1;
			{
				string saving_name = test_reader->root + "classifier_output/bagging/";
				bagging.load(saving_name.c_str());
			}
		}

		vector< LcValidator > validator_array;
		bagging.predict( *test_reader, validator_array);

		for(int i = 0 ; i < (int) validator_array.size() ; i++)
		{
			validator_array[i].display();
		}

		{
			string report_name = "./report/bagging_report_" + my_setting.train_video_name + "_on_"
				+ my_setting.test_video_name + "_v_" + my_setting.feature_code_string + ".txt";
			FILE * fout = fopen( report_name.c_str(),"w");
			for(int i = 0 ; i < (int) validator_array.size() ; i++)
			{
				fprintf(fout,"%f\t%f\t%f\t%f\t%f\n", validator_array[i].getF1(),
					validator_array[i].tp,validator_array[i].fp,validator_array[i].fn,validator_array[i].tn);
			}
			fclose(fout);
		}

	}
	

	//LcVideoReadExt my_reader;

	//{
	//	my_reader.root = "./../../_FGS/";
	//	my_reader.video_name = "GOPR2382_cab";
	//	my_reader.f_start = 550;
	//	my_reader.f_end = 700;
	//	my_reader.f_rate = 50;
	//	my_reader.t_win = 0;
	//	my_reader.veb = 1;
	//}

	//if(0)
	//{

	//	test.setFeatureCode("l");
	//	test.setReader( &my_reader );

	//	test.train( my_reader);
	//	test.save("./");

	//	LcFeatureExtractor my_extractor;

	//	my_extractor.set_extractor( "l" );

	//	test.predict( my_reader).display();

	//}
	//else
	//{
	//	
	//	test.setFeatureCode("l");
	//	test.setReader( &my_reader );
	//	test.setClassifier( new LcRandomTrees);

	//	test.load("./");

	//	vector< LcValidator > validator_array;
	//	test.predict( my_reader, validator_array);

	//	for(int i = 0 ; i < (int) validator_array.size() ; i++)
	//	{
	//		validator_array[i].display();
	//	}
	//}

	//

	return 0;
}